#include "controller.h"
#include "communicationproxy.h"

#include "fuzzypid/fuzzy_PID.h"

#include <QDebug>
#include <QThread>

#define NB -3
#define NM -2
#define NS -1
#define ZO 0
#define PS 1
#define PM 2
#define PB 3

int deltaKpMatrix[7][7]={{PB,PB,PM,PM,PS,ZO,ZO},
                         {PB,PB,PM,PS,PS,ZO,NS},
                         {PM,PM,PM,PS,ZO,NS,NS},
                         {PM,PM,PS,ZO,NS,NM,NM},
                         {PS,PS,ZO,NS,NS,NM,NM},
                         {PS,ZO,NS,NM,NM,NM,NB},
                         {ZO,ZO,NM,NM,NM,NB,NB}};
int deltaKiMatrix[7][7]={{NB,NB,NM,NM,NS,ZO,ZO},
                         {NB,NB,NM,NS,NS,ZO,ZO},
                         {NB,NM,NS,NS,ZO,PS,PS},
                         {NM,NM,NS,ZO,PS,PM,PM},
                         {NM,NS,ZO,PS,PS,PM,PB},
                         {ZO,ZO,PS,PS,PM,PB,PB},
                         {ZO,ZO,PS,PM,PM,PB,PB}};
int deltaKdMatrix[7][7]={{PS,NS,NB,NB,NB,NM,PS},
                         {PS,NS,NB,NM,NM,NS,ZO},
                         {ZO,NS,NM,NM,NS,NS,ZO},
                         {ZO,NS,NS,NS,NS,NS,ZO},
                         {ZO,ZO,ZO,ZO,ZO,ZO,ZO},
                         {PB,NS,PS,PS,PS,PS,PB},
                         {PB,PM,PM,PM,PS,PS,PB}};
float e_mf_paras[]={-3,-3,-2,-3,-2,-1,-2,-1,0,-1,0,1,0,1,2,1,2,3,2,3,3};
float de_mf_paras[]={-3,-3,-2,-3,-2,-1,-2,-1,0,-1,0,1,0,1,2,1,2,3,2,3,3};
float Kp_mf_paras[]={-3,-3,-2,-3,-2,-1,-2,-1,0,-1,0,1,0,1,2,1,2,3,2,3,3};
float Ki_mf_paras[]={-3,-3,-2,-3,-2,-1,-2,-1,0,-1,0,1,0,1,2,1,2,3,2,3,3};
float Kd_mf_paras[]={-3,-3,-2,-3,-2,-1,-2,-1,0,-1,0,1,0,1,2,1,2,3,2,3,3};


Q_GLOBAL_STATIC(Controller, self)


class ControllerPrivate
{
public:
    explicit ControllerPrivate(Controller *obj)
        : q(obj)
    {
        m_communication = new Communication;
        m_communicationProxy = new CommunicationProxy;
        m_communicationProxy->setCommunication(m_communication);
        m_communication->moveToThread(&m_commThread);

        m_fuzzyPID = new FuzzyPID(1500, 650, 0.3, 0.4, 0.2, 0.02, 0.65, 0.005);
        m_fuzzyPID->setMf("trimf", e_mf_paras, "trimf", de_mf_paras, "trimf", Kp_mf_paras, "trimf", Ki_mf_paras, "trimf", Kd_mf_paras);
        m_fuzzyPID->setRuleMatrix(deltaKpMatrix, deltaKiMatrix, deltaKdMatrix);


        QObject::connect(m_communication, &Communication::temperatureChanged
                         , q, &Controller::onTemperatureChanged);
        QObject::connect(q, SIGNAL(adjustValueReady(float))
                         , m_communication, SLOT(onFuzzyPIDAdjustValue(float)));

        m_commThread.start();
    }

    ~ControllerPrivate()
    {
        m_commThread.quit();
        m_commThread.wait();
        delete m_communicationProxy;
        delete m_communication;
        delete m_fuzzyPID;
    }

public:
    Controller *q;

    FuzzyPID *m_fuzzyPID;

    Communication *m_communication;
    CommunicationProxy *m_communicationProxy;
    QThread m_commThread;

    float m_kp;
    float m_ki;
    float m_kd;
    float m_target;
};


Controller *Controller::instance()
{
    return self();
}

Controller::Controller(QObject *parent)
    : QObject(parent)
    , d(new ControllerPrivate(this))
{

}

Controller::~Controller()
{
    delete d;
}

void Controller::setkp(float kp)
{
    if (d->m_kp == kp) {
        return;
    }

    d->m_kp = kp;
    d->m_fuzzyPID->setKp(d->m_kp);
}

float Controller::kp() const
{
    return d->m_kp;
}

void Controller::setki(float ki)
{
    if (d->m_ki == ki) {
        return;
    }

    d->m_ki = ki;
    d->m_fuzzyPID->setKi(d->m_ki);
}

void Controller::setkd(float kd)
{
    if (d->m_kd == kd) {
        return;
    }

    d->m_kd = kd;
    d->m_fuzzyPID->setKd(d->m_kd);
}

void Controller::setTarget(float target)
{
    if (d->m_target == target) {
        return;
    }

    d->m_target = target;
}


CommunicationProxy *Controller::communicationProxy() const
{
    return d->m_communicationProxy;
}

void Controller::onTemperatureChanged(float temperature)
{
    //    qDebug() << m_target <<"    " << actual;
    //    return m_fuzzyPID->realize(m_target, actual);
    //    m_fuzzyPID->showInfo();
    //    float u = 0;
    //    for(int i=0;i<200;i++)
    //        {
    //            u=m_fuzzyPID->realize(m_target, actual);

    //            qDebug()<<i<<"   "<<m_target<<"    "<<actual << " " << u;
    //            actual+=u;
        //        }

    float u = d->m_fuzzyPID->realize(d->m_target, temperature);
    emit adjustValueReady(u);
}
